package cn.mw.cmdb.listener;

import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.exception.InstanceExistException;
import cn.mw.cmdb.exception.InvokeServiceException;
import cn.mw.cmdb.param.ContextAddListener;
import cn.mw.cmdb.param.ContextDeleteListener;
import cn.mw.cmdb.param.ContextEditorListener;
import cn.mw.components.dubbo.config.DubboUtils;
import cn.mw.microMonitorCommon.api.cmdb.InstanceDeleteException;
import cn.mw.microMonitorCommon.api.cmdb.MwCMDBNotify;
import cn.mw.microMonitorCommon.api.common.ServiceException;
import com.beust.jcommander.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 资产验证
 */
@Service
@Slf4j
public class InstanceReleateServiceSyncHandle implements InstanceChangeEventLister {

    private DubboUtils dubboUtils;

    private MessageSource messageSource;

    public InstanceReleateServiceSyncHandle(DubboUtils dubboUtils, MessageSource messageSource) {
        this.dubboUtils = dubboUtils;
        this.messageSource = messageSource;
    }

    @Override
    public Integer getSortLevel() {
        return 10;
    }

    @Override
    public void addReceive(ContextAddListener contextListener) throws Exception {

    }

    @Override
    public Object editorReceive(ContextEditorListener contextListener) throws Exception {
        return null;
    }

    @Override
    public void deleteReceive(ContextDeleteListener contextListener) throws Exception {
        long time1 = System.currentTimeMillis();
        List<String> instanceIds = new ArrayList<>();
        Object param = contextListener.getParam();
        if (param != null && param instanceof List) {
            List<InstanceInfo> instanceInfoList = (List<InstanceInfo>) param;
            for (InstanceInfo instanceInfo : instanceInfoList) {
                instanceIds.add(instanceInfo.getId());
            }

            List<MwCMDBNotify> mwCMDBNotifyServices = dubboUtils.getDubboService(MwCMDBNotify.class);
            if (null != mwCMDBNotifyServices && !instanceIds.isEmpty()) {
                ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
                executor.setCorePoolSize(1);
                executor.setMaxPoolSize(5);
                executor.setQueueCapacity(100);
                executor.setKeepAliveSeconds(60);
                executor.setThreadNamePrefix(InstanceReleateServiceSyncHandle.class.getSimpleName());
                executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
                executor.initialize();
                List<Future<InstanceDeleteException>> futures = new ArrayList<>();
                List<InstanceDeleteException> instanceDeleteExceptionList = new ArrayList<>();
                for (MwCMDBNotify cmdbNotify : mwCMDBNotifyServices) {
                    Future<InstanceDeleteException> future = executor.submit(() -> cmdbNotify.instanceDeleteBefore(instanceIds));
                    futures.add(future);
                }

                StringBuffer stringBuffer = new StringBuffer();
                StringBuffer stringBuffer1 = new StringBuffer();
                String moduleName = messageSource.getMessage("module", null, LocaleContextHolder.getLocale());
                String businessIdName = messageSource.getMessage("businessName", null, LocaleContextHolder.getLocale());
                String instanceIdName = messageSource.getMessage("instanceId", null, LocaleContextHolder.getLocale());
                for (Future<InstanceDeleteException> future : futures) {
                    try {
                        instanceDeleteExceptionList.add(future.get());
                    } catch (ExecutionException e) {
                        Throwable cause = e.getCause();
                        if (cause instanceof ServiceException) {
                            ServiceException serviceException = (ServiceException) cause;
                            stringBuffer1.append(",").append(serviceException.getModule());
                        }
                    }
                }

                executor.shutdown();

                for (InstanceDeleteException instanceDeleteException : instanceDeleteExceptionList) {
                    if (instanceDeleteException != null) {
                        if (CollectionUtils.isNotEmpty(instanceDeleteException.getMessageInfos())) {
                            String messageInfo = Strings.join(",", instanceDeleteException.getMessageInfos());
                            stringBuffer.append(messageInfo);
                        } else {
                            stringBuffer.append(moduleName).append(":").append(instanceDeleteException.getModule()).append(System.lineSeparator());
                            for (Map.Entry<String, List<String>> entry : instanceDeleteException.getBussinessNameMap().entrySet()) {
                                stringBuffer.append(instanceIdName).append(":").append(entry.getKey()).append(System.lineSeparator());
                                stringBuffer.append(businessIdName).append(":").append(System.lineSeparator());
                                StringBuffer sb = new StringBuffer();
                                for (String businessId : entry.getValue()) {
                                    sb.append(",").append(businessId);
                                }
                                stringBuffer.append(sb.substring(1)).append(System.lineSeparator());
                            }
                        }
                    }
                }
                long time2 = System.currentTimeMillis();
                log.info("InstanceReleateServiceSyncHandle：：耗时"+(time2-time1)+"ms");
                if (!stringBuffer.isEmpty()) {
                    InstanceExistException instanceExistException = new InstanceExistException();
                    String[] args = new String[]{stringBuffer.toString()};
                    instanceExistException.setArgs(args);
                    throw instanceExistException;
                }

                if (!stringBuffer1.isEmpty()) {
                    String[] args = new String[]{stringBuffer1.substring(1)};
                    InvokeServiceException invokeServiceException = new InvokeServiceException("invoke-service-error", args);
                    throw invokeServiceException;
                }
            }
        }
    }
}
